# coding:utf-8

from numpy import *
import numpy as np

# 欧式距离(Euclidean Distance)
def oushi_dis(a,b):
    if len(a)==1:
        return abs(a[0]-b[0])
	sum = 0
	for i in range(len(a)):
		sum += (a[i]-b[i])**2
	return sqrt(sum)
#根据公式求解
d1=np.sqrt(np.sum(np.square(x-y)))
#根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X)

#-------------------------------------------------------------

#标准欧式距离 (Standardized Euclidean distance )
'''
将a和b标准化，（值-mean）/std，将方差的倒数看作为一个值，又叫加权欧式距离(Weighted Euclidean distance)
'''
def standardoushi_dis(a,b):
	sumnum = 0
	for i in range(len(a)):
		# 计算si 分量标准差
		avg = (a[i]-b[i])/2
		si = sqrt( (a[i] - avg) ** 2 + (b[i] - avg) ** 2 )
		sumnum += ((a[i]-b[i])/si ) ** 2
	return sqrt(sumnum)

X=np.vstack([x,y])
#根据公式求解
sk=np.var(X,axis=0,ddof=1)
d1=np.sqrt(((x - y) ** 2 /sk).sum())

#根据scipy库求解
from scipy.spatial.distance import pdist
d2=pdist(X,'seuclidean')
#-------------------------------------------------------------

#曼哈顿距离(Manhattan Distance)/城市街区距离(City Block distance)
def manhattan_dis(a,b):
	sum = 0 
	for i in range(len(a)):
		sum += abs(a[i]-b[i])
	return sum
#根据公式求解
d1=np.sum(np.abs(x-y))

#根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'cityblock')
#-------------------------------------------------------------

#切比雪夫距离( Chebyshev Distance )
def qbxf_dis(a,b):
	maxnum = 0
	for i in range(len(a)):
		if abs(a[i]-b[i]) > maxnum:
			maxnum = abs(a[i]-b[i])
	return maxnum
#根据公式求解
d1=np.max(np.abs(x-y))

#根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'chebyshev')
#-------------------------------------------------------------

#夹角余弦
def cos_dis(a,b):
    sum_fenzi = 0.0
    sum_fenmu_1,sum_fenmu_2 = 0,0
    for i in range(len(a)):
        sum_fenzi += a[i]*b[i]
        sum_fenmu_1 += a[i]**2 
        sum_fenmu_2 += b[i]**2 
    return sum_fenzi/( sqrt(sum_fenmu_1) * sqrt(sum_fenmu_2) )
#根据公式求解
d1=np.dot(x,y)/(np.linalg.norm(x)*np.linalg.norm(y))

#根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=1-pdist(X,'cosine')
#-------------------------------------------------------------

#汉明距离
'''a变成b的最小替换次数'''
def hanming_dis(a,b):
	sumnum = 0
	for i in range(len(a)):
		if a[i]!=b[i]:
			sumnum += 1
	return sumnum
#根据公式求解
d1=np.mean(x!=y)

#根据scipy库求解
X=np.vstack([x,y])
d2=pdist(X,'hamming')
#-------------------------------------------------------------

#杰卡德距离(Jaccard)
'''杰卡德距离用两个集合中不同元素占所有元素的比例来衡量两个集合的区分度。'''
def jiekade_dis(a,b):
	set_a = set(a)
	set_b = set(b)
	dis = float(len( (set_a | set_b) - (set_a & set_b) ) )/ len(set_a | set_b)
	return dis
#根据公式求解
up=np.double(np.bitwise_and((x != y),np.bitwise_or(x != 0, y != 0)).sum())
down=np.double(np.bitwise_or(x != 0, y != 0).sum())
d1=(up/down)

#根据scipy库求解
X=np.vstack([x,y])
d2=pdist(X,'jaccard')

#-------------------------------------------------------------

#杰卡德相似系数
'''
两个集合A和B的交集元素在A，B的并集中所占的比例，称为两个集合的杰卡德相似系数
可用在衡量样本的相似度上
'''
def jiekadeXS_dis(a,b):
	set_a = set(a)
	set_b = set(b)
	dis = float(len(set_a & set_b)  )/ len(set_a | set_b)
	return dis

#-------------------------------------------------------------

#闵可夫斯基距离(MinkowskiDistance)
'''
两值相差绝对值的p次方后开p次
当p=1时，就是曼哈顿距离
当p=2时，就是欧氏距离
当p→∞时，就是切比雪夫距离
'''
#根据公式求解,p=2
d1=np.sqrt(np.sum(np.square(x-y)))

#根据scipy库求解
from scipy.spatial.distance import pdist
X=np.vstack([x,y])
d2=pdist(X,'minkowski',p=2)

#-------------------------------------------------------------

#马氏距离(Mahalanobis Distance)
'''
S为协方差矩阵，公式为：(a-b)(S的逆矩阵)(a-b)开方，若逆矩阵为单位矩阵（各个样本向量之间独立同分布），公式等价于欧式距离
若协方差矩阵是对角矩阵，公式变成了标准化欧氏距离。

1）马氏距离的计算是建立在总体样本的基础上的，这一点可以从上述协方差矩阵的解释中可以得出，也就是说，
如果拿同样的两个样本，放入两个不同的总体中，最后计算得出的两个样本间的马氏距离通常是不相同的，
除非这两个总体的协方差矩阵碰巧相同；

2）在计算马氏距离过程中，要求总体样本数大于样本的维数，否则得到的总体样本协方差矩阵逆矩阵不存在，
这种情况下，用欧式距离计算即可。

3）还有一种情况，满足了条件总体样本数大于样本的维数，但是协方差矩阵的逆矩阵仍然不存在，
比如三个样本点（3，4），（5，6）和（7，8），这种情况是因为这三个样本在其所处的二维空间平面内共线。采用欧式距离计算。

4）在实际应用中“总体样本数大于样本的维数”这个条件是很容易满足的，而所有样本点出现3）中所描述的情况是很少出现的，
所以在绝大多数情况下，马氏距离是可以顺利计算的，但是马氏距离的计算是不稳定的，不稳定的来源是协方差矩阵，
这也是马氏距离与欧式距离的最大差异之处。

优点：它不受量纲的影响，两点之间的马氏距离与原始数据的测量单位无关；
由标准化数据和中心化数据(即原始数据与均值之差）计算出的二点之间的马氏距离相同。
马氏距离还可以排除变量之间的相关性的干扰。缺点：它的缺点是夸大了变化微小的变量的作用。
'''
x=np.random.random(10)
y=np.random.random(10)

#马氏距离要求样本数要大于维数，否则无法求协方差矩阵
#此处进行转置，表示10个样本，每个样本2维
X=np.vstack([x,y])
XT=X.T

#方法一：根据公式求解
S=np.cov(X)   #两个维度之间协方差矩阵
SI = np.linalg.inv(S) #协方差矩阵的逆矩阵
#马氏距离计算两个样本之间的距离，此处共有10个样本，两两组合，共有45个距离。
n=XT.shape[0]
d1=[]
for i in range(0,n):
    for j in range(i+1,n):
        delta=XT[i]-XT[j]
        d=np.sqrt(np.dot(np.dot(delta,SI),delta.T))
        d1.append(d)
        
#方法二：根据scipy库求解
from scipy.spatial.distance import pdist
d2=pdist(XT,'mahalanobis')

#-------------------------------------------------------------

#皮尔逊相关系数（Pearson correlation）
'''皮尔逊相关系数具有平移不变性和尺度不变性，计算出了两个向量（维度）的相关性'''
import numpy as np
x=np.random.random(10)
y=np.random.random(10)

#方法一：根据公式求解
x_=x-np.mean(x)
y_=y-np.mean(y)
d1=np.dot(x_,y_)/(np.linalg.norm(x_)*np.linalg.norm(y_))

#方法二：根据numpy库求解
X=np.vstack([x,y])
d2=np.corrcoef(X)[0][1]

#-------------------------------------------------------------

#布雷柯蒂斯距离(Bray Curtis Distance)
import numpy as np
from scipy.spatial.distance import pdist
x=np.array([11,0,7,8,0])
y=np.array([24,37,5,18,1])

#方法一：根据公式求解
up=np.sum(np.abs(y-x))
down=np.sum(x)+np.sum(y)
d1=(up/down)
           
#方法二：根据scipy库求解
X=np.vstack([x,y])
d2=pdist(X,'braycurtis')